﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;

namespace XML
{
    public static class XMLReader
    {
        public static Map ReadMap(string path)
        {
            Exception excMap = new Exception("Map is invalid!");
            Exception excTile = new Exception("Map is invalid at tiles!");
            int x = 0, y = 0, currentX = 0, currentY = 0;
            Map map = new Map();
            XmlReader reader = XmlReader.Create(path);
            reader.Read();
            reader.Read();
            while (reader.Read())
            {
                if (reader.IsStartElement())
                {
                    switch (reader.Name)
                    {
                        case "name":
                            {
                                map.Name = reader.GetAttribute("val");
                                break;
                            }
                        case "x":
                            {
                                x = int.Parse(reader.GetAttribute("val"));
                                break;
                            }
                        case "y":
                            {
                                y = int.Parse(reader.GetAttribute("val"));
                                break;
                            }
                        case "tiles":
                            {
                                if (map.OriginalGridMatrix != null)
                                {
                                    throw excMap;
                                }
                                map.OriginalGridMatrix = new AbstractBox[y, x];
                                for (int i = 0; i < y; i++)
                                {
                                    for (int j = 0; j < x; j++)
                                    {                                     
                                        reader.Read();
                                        reader.Read();
                                        if (reader.Name != "tile")
                                        {
                                            throw excTile;
                                        }

                                        reader.Read();
                                        reader.Read();
                                        if (reader.Name != "x")
                                        {
                                            throw excTile;
                                        }
                                        currentX = int.Parse(reader.GetAttribute("pos"));

                                        reader.Read();
                                        reader.Read();
                                        if (reader.Name != "y")
                                        {
                                            throw excTile;
                                        }
                                        currentY = int.Parse(reader.GetAttribute("pos"));

                                        reader.Read();
                                        reader.Read();
                                        if (reader.Name == "type")
                                        {
                                            switch (reader.GetAttribute("val"))
                                            {
                                                case "box":
                                                    {
                                                        map.OriginalGridMatrix[j, i] = new Box(currentX, currentY);
                                                        break;
                                                    }
                                                case "empty":
                                                    {
                                                        map.OriginalGridMatrix[j, i] = new Empty(currentX, currentY);
                                                        break;
                                                    }
                                                case "goal":
                                                    {
                                                        map.OriginalGridMatrix[j, i] = new Goal(currentX, currentY);
                                                        break;
                                                    }
                                                case "player":
                                                    {
                                                        map.OriginalGridMatrix[j, i] = new Player(currentX, currentY);
                                                        break;
                                                    }
                                                case "wall":
                                                    {
                                                        map.OriginalGridMatrix[j, i] = new Wall(currentX, currentY);
                                                        break;
                                                    }
                                                default:
                                                    throw excTile;
                                            }


                                        }
                                        else throw excTile;

                                        reader.Read();
                                        reader.Read();                                      
                                    }
                                }
                                reader.Read();
                                reader.Read();
                                break;
                            }
                        default:
                            throw excMap;
                    }
                }
            }

            return map;
        }
    }
}
